import 'dart:convert';

import 'package:shared_preferences/shared_preferences.dart';
import 'package:synchronized/synchronized.dart';

class SpUtil {
  /// 内部构造方法，可避免外部暴露构造函数，进行实例化（单例模式）
  SpUtil._();

  static late SpUtil _instance;
  static late SharedPreferences _prefs;

  Future _init() async {
    _prefs = await SharedPreferences.getInstance();
  }

  /// 获取单例内部方法
  static Future<SpUtil> getInstance() async {
    if (_instance == null) {
      await Lock().synchronized(() async {
        if (_instance == null) {
          var instance = SpUtil._();
          await instance._init();
          _instance = instance;
        }
      });
    }
    return _instance;
  }

  static Future<bool> _putFailed() => Future.value(false);

  /// put int.
  static Future<bool> putInt(String key, int value) =>
      _prefs == null ? _putFailed() : _prefs.setInt(key, value);

  /// get int.
  static int getInt(String key, {int defValue = 0}) =>
      _prefs == null ? defValue : _prefs.getInt(key) ?? defValue;

  /// put double.
  static Future<bool> putDouble(String key, double value) =>
      _prefs == null ? _putFailed() : _prefs.setDouble(key, value);

  /// get double.
  static double getDouble(String key, {double defValue = 0.0}) =>
      _prefs == null ? defValue : _prefs.getDouble(key) ?? defValue;

  /// put bool.
  static Future<bool> putBool(String key, bool value) =>
      _prefs == null ? _putFailed() : _prefs.setBool(key, value);

  /// get bool.
  static bool getBool(String key, {bool defValue = false}) =>
      _prefs == null ? defValue : _prefs.getBool(key) ?? defValue;

  /// put string.
  static Future<bool> putString(String key, String value) =>
      _prefs == null ? _putFailed() : _prefs.setString(key, value);

  /// get string.
  static String getString(String key, {String defValue = ''}) =>
      _prefs == null ? defValue : _prefs.getString(key) ?? defValue;

  /// put string list.
  static Future<bool> putStringList(String key, List<String> value) =>
      _prefs == null ? _putFailed() : _prefs.setStringList(key, value);

  /// get string list.
  static List<String> getStringList(String key,
          {List<String> defValue = const []}) =>
      _prefs == null ? defValue : _prefs.getStringList(key) ?? defValue;

  /// put object.
  static Future<bool> putObject(String key, Object value) {
    return _prefs == null
        ? _putFailed()
        : _prefs.setString(key, value == null ? "" : json.encode(value));
  }

  /// get obj.
  static T getObj<T>(String key, T f(Map v), {required T defValue}) {
    Map? map = getObject(key);
    return map == null ? defValue : f(map);
  }

  /// get object.
  static Map? getObject(String key) {
    if (_prefs == null) return null;
    String _data = _prefs.getString(key);
    return (_data == null || _data.isEmpty) ? null : json.decode(_data);
  }

  /// put object list.
  static Future<bool> putObjectList(String key, List<Object> list) {
    if (_prefs == null) return _putFailed();
    List<String> _dataList = list.map((value) => json.encode(value)).toList();
    return _prefs.setStringList(key, _dataList);
  }



  /// get dynamic.
  static dynamic getDynamic(String key, {required Object defValue}) =>
      _prefs == null ? defValue : _prefs.get(key) ?? defValue;

  /// have key.
  static bool haveKey(String key) =>
      _prefs == null ? false : _prefs.getKeys().contains(key);

  /// get keys.
  static Set<String> getKeys() =>
      _prefs == null ? Set<String>() : _prefs.getKeys();

  /// remove.
  static Future<bool> remove(String key) =>
      _prefs == null ? _putFailed() : _prefs.remove(key);

  /// clear.
  static Future<bool> clear() => _prefs == null ? _putFailed() : _prefs.clear();

  /// Sp is initialized.
  static bool isInitialized() => _prefs != null;
}
